package org.smile.http;

import java.net.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.smile.beans.converter.BasicConverter;
import org.smile.beans.converter.ConvertException;
import org.smile.beans.converter.type.IntArrayConverter;
import org.smile.collection.KeyNoCaseHashMap;
import org.smile.collection.ResultMap;
import org.smile.commons.SmileRunException;
import org.smile.commons.Strings;
import org.smile.io.BufferedReader;
import org.smile.log.LoggerHandler;
import org.smile.util.RegExp;
import org.smile.util.StringUtils;

public class IpUtils implements LoggerHandler {

	/**
	 * 本地ip
	 */
	public static String getLocalIp() {
		String ip = Strings.BLANK;
		try {
			InetAddress addr = InetAddress.getLocalHost();
			ip = addr.getHostAddress();
		} catch (UnknownHostException e) {
			logger.error("获取本地ip异常", e);
		}
		return ip;
	}

	/**
	 * 获取远程IP,可能是nginx代理
	 * @param request
	 * @return
	 */
	public static String getRequestRemoteIP(HttpServletRequest request){
		Enumeration names=request.getHeaderNames();
		Map<String,String> headers=new KeyNoCaseHashMap<>();
		while(names.hasMoreElements()){
			String name=names.nextElement().toString();
			headers.put(name, request.getHeader(name));
		}
		String ip=headers.get("X-Real-IP");
		if (!checkHasIp(ip)) {
			ip = headers.get("x-forwarded-for");
		}else{
			return ip;
		}
		if (!checkHasIp(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}else{
			return ip;
		}
		if (!checkHasIp(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}else{
			return ip;
		}
		if(!checkHasIp(ip)){
			ip=request.getRemoteAddr();
		}else{
			return ip;
		}
		return ip;
	}

	/**
	 * 客户端ip
	 */
	public static String getClientIpAddr(HttpServletRequest request) {
		String ip = request.getRemoteAddr();
		if (!checkHasIp(ip)) {
			ip = request.getHeader("x-forwarded-for");
		}
		if (!checkHasIp(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (!checkHasIp(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		return ip;
	}

	/**
	 * 是否存在IP
	 * @param ip
	 * @return
	 */
	private static boolean checkHasIp(String ip){
		return !(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip));
	}


	/**
	 * 判断是否ip地址
	 *
	 * @param ipAddress
	 * @return
	 */
	public static boolean isIpAddress(String ipAddress) {
		String ip = "(2[5][0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})";
		Pattern pattern = Pattern.compile(ip);
		Matcher matcher = pattern.matcher(ipAddress);
		return matcher.matches();
	}

	/***
	 * 网页内容
	 * @param urlStr
	 * @return
	 */
	public static String getUrlContent(String urlStr, String charset) {
		StringBuffer add = new StringBuffer();
		try {
			String city = null;
			URL url = new URL(urlStr);
			URLConnection conn = url.openConnection();
			BufferedReader reader = new BufferedReader(conn.getInputStream(), charset);
			while ((city = reader.readLine()) != null) {
				add.append(city);
			}
			reader.close();
		} catch (Exception e) {
			logger.error("connection ulr " + urlStr + " error charset :" + charset, e);
		}
		return add.toString();
	}

	/**
	 * 调用第三方接口，根据IP地址获取城市信息，如果第三方接口不可用了请更改此方法
	 * http://whois.pconline.com.cn/ip.jsp?ip= ipAdress
	 * @param ipAddress
	 * @return
	 */
	public static String getCityByIpName(String ipAddress){
		String city = getUrlContent("http://whois.pconline.com.cn/ip.jsp?ip="+ipAddress,"GBK");
		String nul[] = city.split("市");
		if (nul.length > 1)
			city = nul[0];
		String all[] = city.split("省");
		if (all.length > 1)
			city = all[1];
		if (city.equals("局域网对方和您在同一内部网"))
			city = "内网";
		return city;
	}

	/**
	 * @param ip    要验证的ip
	 * @param start 起始
	 * @param end   结束
	 * @return
	 */
	public static boolean ipCheckRange(String ip, String start, String end) {
		try {
			Integer[] ipInts = IntArrayConverter.getInstance().convert(StringUtils.splitc(ip, '.'));
			Integer[] startInts = IntArrayConverter.getInstance().convert(StringUtils.splitc(start, '.'));
			Integer[] endInts = IntArrayConverter.getInstance().convert(StringUtils.splitc(end, '.'));
			for(int i=0;i<ipInts.length;i++){
				if(i<startInts.length){
					if(ipInts[i]<startInts[i]){
						return false;
					}
				}
				if(i<endInts.length){
					if(ipInts[i]>endInts[i]){
						return false;
					}
				}
			}
			return true;
		} catch (ConvertException e) {
			throw new SmileRunException("ip error",e);
		}
	}

	public static LinkedHashSet<String> localIpv4s() {
		LinkedHashSet<InetAddress> localAddressList = localAddressList((t) -> {
			return t instanceof Inet4Address;
		});
		return toIpList(localAddressList);
	}

	public static LinkedHashSet<String> localIpv6s() {
		LinkedHashSet<InetAddress> localAddressList = localAddressList((t) -> {
			return t instanceof Inet6Address;
		});
		return toIpList(localAddressList);
	}

	public static LinkedHashSet<InetAddress> localAddressList(Filter<InetAddress> addressFilter) {
		return localAddressList((Filter)null, addressFilter);
	}

	public static LinkedHashSet<String> toIpList(Set<InetAddress> addressList) {
		LinkedHashSet<String> ipSet = new LinkedHashSet();
		Iterator var2 = addressList.iterator();

		while(var2.hasNext()) {
			InetAddress address = (InetAddress)var2.next();
			ipSet.add(address.getHostAddress());
		}

		return ipSet;
	}

	public static LinkedHashSet<InetAddress> localAddressList(Filter<NetworkInterface> networkInterfaceFilter, Filter<InetAddress> addressFilter) {
		Enumeration networkInterfaces;
		try {
			networkInterfaces = NetworkInterface.getNetworkInterfaces();
		} catch (SocketException var7) {
			throw new SmileRunException(var7);
		}

		if (networkInterfaces == null) {
			throw new SmileRunException("Get network interface error!");
		} else {
			LinkedHashSet ipSet = new LinkedHashSet();

			label52:
			while(true) {
				NetworkInterface networkInterface;
				do {
					if (!networkInterfaces.hasMoreElements()) {
						return ipSet;
					}

					networkInterface = (NetworkInterface)networkInterfaces.nextElement();
				} while(networkInterfaceFilter != null && !networkInterfaceFilter.accept(networkInterface));

				Enumeration inetAddresses = networkInterface.getInetAddresses();

				while(true) {
					InetAddress inetAddress;
					do {
						do {
							if (!inetAddresses.hasMoreElements()) {
								continue label52;
							}

							inetAddress = (InetAddress)inetAddresses.nextElement();
						} while(inetAddress == null);
					} while(null != addressFilter && !addressFilter.accept(inetAddress));

					ipSet.add(inetAddress);
				}
			}
		}
	}

	@FunctionalInterface
	public interface Filter<T> {
		boolean accept(T var1);
	}

}
